package cn.ztydata.teachingsystem.heaven.web.exception.advice;

import cn.ztydata.teachingsystem.exception.ServiceException;
import cn.ztydata.teachingsystem.webservice.dto.validation.ValidationErrorDto;
import cn.ztydata.teachingsystem.webservice.result.json.JsonResult;
import cn.ztydata.teachingsystem.webservice.result.json.JsonResultData;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.TypeMismatchException;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;

import java.util.List;

/**
 * 异常处理类
 * Created by chenxin on 2014/10/20.
 */
@ControllerAdvice
public class GlobalDefaultExceptionHandler {
    private static final Logger log = LoggerFactory.getLogger(GlobalDefaultExceptionHandler.class); //日志记录器

    /**
     * 捕获业务逻辑异常
     * @param ex 异常类
     * @return json
     *
     * @author cx
     * @since 2015-02-06
     */
    @ExceptionHandler(ServiceException.class)
    @ResponseBody
    public JsonResult serviceErrorHandler(Exception ex) {
        //记录日志
        log.warn("业务处理异常", ex);

        return new JsonResult(false, ex.getMessage() == null ? "操作失败" : ex.getMessage());
    }

    /**
     * 捕获Assert校验异常
     * @param ex 异常类
     * @return json
     *
     * @author cx
     * @since 2014-11-27
     */
    @ExceptionHandler({MissingServletRequestParameterException.class, TypeMismatchException.class, IllegalStateException.class, IllegalArgumentException.class})
    @ResponseStatus(value = HttpStatus.BAD_REQUEST)
    @ResponseBody
    public JsonResult argsErrorHandler(Exception ex) {
        //记录日志
        log.warn("数据校验异常捕获", ex);

        return new JsonResult(false, "请求中存在错误参数");
    }

    /**
     * 捕获注解校验异常
     * @param ex 异常类
     * @return json
     *
     * @author cx
     * @since 2014-11-27
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(value = HttpStatus.BAD_REQUEST)
    @ResponseBody
    public JsonResult argsErrorHandler(MethodArgumentNotValidException ex) {
        //记录日志
        log.warn("数据校验异常捕获", ex);

        BindingResult result = ex.getBindingResult();
        List<FieldError> fieldErrors = result.getFieldErrors();

        return new JsonResultData<>(false, "参数校验失败", processFieldErrors(fieldErrors));
    }

    /**
     * 处理捕获到的错误字段
     * @param fieldErrors 错误字段集合
     * @return ValidationErrorDto
     *
     * @author cx
     * @since 2014-11-27
     */
    private ValidationErrorDto processFieldErrors(List<FieldError> fieldErrors) {
        ValidationErrorDto dto = new ValidationErrorDto();

        for (FieldError fieldError: fieldErrors) {
            dto.addFieldError(fieldError.getField(), fieldError.getDefaultMessage());
        }

        return dto;
    }

    /**
     * 统一捕获异常
     * @param ex 异常类
     * @return json
     *
     * @author cx
     * @since 2014-11-27
     */
    @ExceptionHandler(value = Exception.class)
    @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
    @ResponseBody
    public JsonResult defaultErrorHandler(Exception ex) {
        //记录日志
        log.warn("统一捕获异常处理", ex);

        return new JsonResult(false, "操作处理出现错误");
    }
}
